import 'dart:async';
import 'package:crypto/crypto.dart';
import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'dart:async' show Future;
import 'dart:io';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'dart:math';
import 'util/database.dart';

void toast(String text) async {
  Fluttertoast.showToast(msg: text);
}

String getTimeLong(int time) {
  var time_long = new DateTime.now().millisecondsSinceEpoch - time * 1000;
  return (time_long / 1000 / 60 / 60 / 24).toStringAsFixed(0) + "天";
}

String converTime(int time) {
  var dt = new DateTime.fromMillisecondsSinceEpoch(time * 1000);
  return dt.toString().substring(0, 19);
}

String convertSize(String num) {
  if (num == "") {
    return "获取中";
  }
  double byte = double.parse(num);
  if (byte < 1024) {
    return "$byte B";
  } else if (byte < 1024 * 1024) {
    return (byte / 1024).toStringAsFixed(1) + "K";
  } else if (byte < 1024 * 1024 * 1024) {
    return (byte / 1024 / 1024).toStringAsFixed(1) + "M";
  } else if (byte < 1024 * 1024 * 1024 * 1024) {
    return (byte / 1024 / 1024 / 1024).toStringAsFixed(1) + "G";
  } else {
    return (byte / 1024 / 1024 / 1024 / 1024).toStringAsFixed(1) + "T";
  }
}

String signPwd(String password) {
  var str = md5.convert(utf8.encode(password)).toString();
  var c1 = str[2], c2 = str[8], c3 = str[17], c4 = str[27];
  str = str.substring(0, 2) + c2 + str.substring(3, 8) + c1 + str.substring(9, 17) + c4 + str.substring(18, 27) + c3 + str.substring(28, 32);
  str = md5.convert(utf8.encode(str)).toString();
  return str;
}

String rand() {
  var r = Random().nextInt(2147483646);
  return r.toString();
}

Future<dynamic> post({String url, Map data, Map<String, dynamic> header, String contentType}) async {
  if (header == null) {
    header = {"Cache-Control": "no-cache"};
  }
  if (contentType == null) {
    contentType = "application/x-www-form-urlencoded";
  }
  Dio dio = new Dio(
    new Options(
      contentType: ContentType.parse(contentType),
      headers: header,
    ),
  );
  Response response;
  response = await dio.post(
    url,
    data: data,
  );
  var res;
  var cookie = response.headers['set-cookie'];
  if (response.data.runtimeType.toString() == "String") {
    res = json.decode(response.data);
  } else {
    res = response.data;
  }
  res['cookie'] = cookie;
  return res;
}

Future<dynamic> get(String url, Map data, Map header) async {
  Dio dio = new Dio(
    new Options(
      contentType: ContentType.parse("application/x-www-form-urlencoded"),
      headers: header,
    ),
  );
  Response response = await dio.get(
    url,
    data: data,
  );
  var res;
  if (response.data.runtimeType.toString() == "String") {
    res = json.decode(response.data);
  } else {
    res = response.data;
  }
  return res;
}

Future<bool> setStorage(String name, String value) async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  return prefs.setString(name, value);
}

Future<String> getStorage(String name) async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  return prefs.getString(name);
}

Future<bool> removeStorage(String name) async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  return prefs.remove(name);
}

//dynamic jsonDecode(String json){
//  return jsonDecode(json);
//}
Map getParams(Map data, String sessionid, bool isGet) {
  var str = "";
  data.forEach((k, v) {
    str += "$k=$v&";
  });
  str = str.substring(0, str.length - 1);
  str += "&key=" + sessionid;
  if (isGet) {
    data['sign'] = md5.convert(utf8.encode(str)).toString();
  } else {
    data['key'] = sessionid;
    data['sign'] = md5.convert(utf8.encode(str)).toString();
  }

  return data;
}

Future<List> getGroups() async {
  WankeData groups = new WankeData(tableName: "groups");
  await groups.iniSqlite();
  if (groups.db != null) {
    List<Map> rows = await groups.select();
    return rows;
  } else {
    return null;
  }
}

Future<List> getDevicesByGroup(int id) async {
  WankeData devices = new WankeData(tableName: "devices");
  await devices.iniSqlite();
  if (devices.db != null) {
    List<Map> rows = await devices.selectByColumn("group_id", id);
    return rows;
  } else {
    return null;
  }
}

Future<int> addGroup(String name) async {
  WankeData groups = new WankeData(tableName: "groups");
  await groups.iniSqlite();
  if (groups.db != null) {
    Map<String, dynamic> data;
    data = {"name": name};
    var result = await groups.insert(data);
    return result;
  } else {
    return null;
  }
}

Future<bool> findDeviceByAccount(String account) async {
  WankeData devices = new WankeData(tableName: "devices");
  await devices.iniSqlite();
  if (devices.db != null) {
    var result = await devices.findByColumn("account", account);
    return result != null;
  } else {
    return false;
  }
}

Future<Map> findDeviceById(dynamic id) async {
  id = id.toString();
  WankeData devices = new WankeData(tableName: "devices");
  await devices.iniSqlite();
  if (devices.db != null) {
    var result = await devices.findByColumn("id", id);
    return result;
  } else {
    return null;
  }
}

Future<int> getDeviceCount() async {
  WankeData devices = new WankeData(tableName: "devices");
  await devices.iniSqlite();
  if (devices.db != null) {
    var result = await devices.rowCount();
    return result;
  } else {
    return 0;
  }
}

Future<int> addDevice(int group_id, String account, String password, String deviceid, String imeiid, String sessionid, String userid) async {
  WankeData devices = new WankeData(tableName: "devices");
  await devices.iniSqlite();
  if (devices.db != null) {
    Map<String, dynamic> data;
    data = {"group_id": group_id, "account": account, "password": password, "deviceid": deviceid, "imeiid": imeiid, "sessionid": sessionid, "userid": userid, "name": "获取中", "is_bind": "1"};
    var result = await devices.insert(data);
    return result;
  } else {
    return null;
  }
}

Future<bool> deleteDeviceById(int id) async {
  WankeData devices = new WankeData(tableName: "devices");
  await devices.iniSqlite();
  if (devices.db != null) {
    var result = await devices.deleteByColumn("id", id.toString());
    return result > 0 ? true : false;
  } else {
    return null;
  }
}

Future<bool> updateDevice({
  int id,
  String device_name,
  String password,
  String sessionid,
  String userid,
  String capacity,
  String used,
  String addr,
  String device_id,
  String device_sn,
  String peerid,
  String system_version,
  String ip_addr,
  String mac_address,
  String lan_ip,
  String province,
  String city,
  String isp,
  String status,
  String bind_time,
  String bind_days,
  String hardware_model,
  String is_bind,
  String iswanke,
  String ispush,
  int group_id,
}) async {
  if (id == null) return false;
  WankeData devices = new WankeData(tableName: "devices");
  await devices.iniSqlite();
  if (devices.db != null) {
    Map<String, dynamic> data = {"id": id};
    if (device_name != null) data['device_name'] = device_name;
    if (password != null) data['password'] = password;
    if (sessionid != null) data['sessionid'] = sessionid;
    if (userid != null) data['userid'] = userid;
    if (capacity != null) data['capacity'] = capacity;
    if (used != null) data['used'] = used;
    if (addr != null) data['addr'] = addr;
    if (device_id != null) data['device_id'] = device_id;
    if (device_sn != null) data['device_sn'] = device_sn;
    if (peerid != null) data['peerid'] = peerid;
    if (system_version != null) data['system_version'] = system_version;
    if (ip_addr != null) data['ip_addr'] = ip_addr;
    if (ip_addr != null) data['ip_addr'] = ip_addr;
    if (mac_address != null) data['mac_address'] = mac_address;
    if (lan_ip != null) data['lan_ip'] = lan_ip;
    if (province != null) data['province'] = province;
    if (city != null) data['city'] = city;
    if (isp != null) data['isp'] = isp;
    if (status != null) data['status'] = status;
    if (bind_time != null) data['bind_time'] = bind_time;
    if (bind_days != null) data['bind_days'] = bind_days;
    if (hardware_model != null) data['hardware_model'] = hardware_model;
    if (is_bind != null) data['is_bind'] = is_bind;
    if (iswanke != null) data['iswanke'] = iswanke;
    if (ispush != null) data['ispush'] = ispush;
    var result = await devices.update(data);
    if (result > 0) {
      return true;
    } else {
      return false;
    }
  } else {
    return null;
  }
}

Future<Map> doLogin({
  int id,
  String account,
  String password,
  String deviceid,
  String imeiid,
}) async {
  if (deviceid == null) deviceid = rand();
  if (imeiid == null) imeiid = rand();
  Map data;
  //判断账号类型
  if (account.contains("@")) {
    print("邮箱账号");
    data = {
      'account_type': '5',
      'deviceid': deviceid,
      'imeiid': imeiid,
      'mail': account,
      'phone_area': "Email",
      'pwd': signPwd(password),
    };
  } else {
    print("手机账号");
    data = {
      'account_type': '4',
      'deviceid': deviceid,
      'imeiid': imeiid,
      'phone': account,
      'pwd': signPwd(password),
    };
  }
  //d232bdca7ef9b4e4971ed1ed006721f8
  var url = "https://api-accw.onethingpcs.com/user/login?appversion=1.5.2";

  data = getParams(data, "", false);
  var res = await post(url: url, data: data);
  if (res['iRet'] == 0) {
    List<String> cookies = res['cookie'];
    Map info = {"sessionid": "", "userid": ""};
    cookies.forEach((cookie) {
      if (cookie.contains("sessionid")) {
        info['sessionid'] = cookie.substring(10, 42);
      } else if (cookie.contains("userid")) {
        info['userid'] = cookie.substring(7, 14);
      }
    });
    updateDevice(id: id, sessionid: info['sessionid'], used: info['userid']);
    return info;
  } else {
    toast(res['sMsg']);
    return null;
  }
}

Future<bool> checkLogin(
  String sessionid,
  String userid,
) async {
  var url = 'https://api-accw.onethingpcs.com/user/check-session?appversion=1.5.2';
  var header = {"Cookie": "sessionid=$sessionid; userid=$userid"};
  var sign = md5.convert(utf8.encode("&key=$sessionid"));
  var data = {"sign": sign};
  var res = await post(url: url, data: data, header: header);
  if (res['iRet'] == 0) {
    return true;
  } else {
    return false;
  }
}

Future<List> getDeviceInfo(String sessionid, String userid) async {
  Map<String, dynamic> data = {'appversion': '1.5.10', 'ct': 1, 'v': 1};
  data = getParams(data, sessionid, true);
  var url = "https://control.onethingpcs.com/listPeer";
  var header = {"Cookie": "sessionid=" + sessionid + "; userid=" + userid};
  var res = await get(url, data, header);
  if (res['rtn'] != 0) {
    return null;
  } else {
    List bindDevices = res['result'][1]['devices'];
    return bindDevices;
  }
}

void showPopupMenu<T>(BuildContext context, State state,
    {double elevation = 8.0, @required List<PopupMenuEntry<T>> items, T initialValue, PopupMenuCanceled onCanceled, PopupMenuItemSelected<T> onSelected, double offsetX = 0.0, double offsetY = 0.0}) {
  final RenderBox button = context.findRenderObject();
  final RenderBox overlay = Overlay.of(context).context.findRenderObject();
  final RelativeRect position = new RelativeRect.fromRect(
    new Rect.fromPoints(
      button.localToGlobal(new Offset(offsetX, offsetY), ancestor: overlay),
      button.localToGlobal(button.size.bottomRight(Offset.zero), ancestor: overlay),
    ),
    Offset.zero & overlay.size,
  );
  showMenu<T>(
    context: context,
    elevation: elevation,
    items: items,
    initialValue: initialValue,
    position: position,
  ).then<void>((T newValue) {
    if (!state.mounted) return null;
    if (newValue == null) {
      if (onCanceled != null) onCanceled();
      return null;
    }
    if (onSelected != null) onSelected(newValue);
  });
}

Future<bool> bindDevice(String sessionid, String userid, String device_id) async {
  Map<String, dynamic> data = {'appversion': '1.5.10', 'ct': 2, 'deviceid': device_id, 'userud': userid, 'v': 1};
  data = getParams(data, sessionid, true);
  var url = "https://control.onethingpcs.com/bind";
  var header = {"Cookie": "sessionid=" + sessionid + "; userid=" + userid};
  var res = await get(url, data, header);
  if (res['rtn'] != 0) {
    toast(res['msg']);
    return false;
  } else {
    return true;
  }
}

Future<bool> unBindDevice(String sessionid, String userid, String device_id) async {
  Map<String, dynamic> data = {'appversion': '1.5.10', 'device_id': device_id, 'nc': 'IN', 'v': 1};
  data = getParams(data, sessionid, true);
  var url = "https://control.onethingpcs.com/unbind";
  var header = {"Cookie": "sessionid=" + sessionid + "; userid=" + userid};
  var res = await get(url, data, header);
  if (res['rtn'] != 0) {
    toast(res['msg']);
    return false;
  } else {
    return true;
  }
}

Future<Map> getDrawRecord(String sessionid, String userid) async {
  var header = {"Cookie": "sessionid=" + sessionid + "; userid=" + userid};
  var res = await post(url: "https://api-accw.onethingpcs.com/wkb/outcome-history", header: header);
  if (res['iRet'] != 0) {
    toast("加载失败");
    return null;
  } else {
    return res['data'];
  }
}

Future<String> applyToDraw(String sessionid, String userid) async {
  Map<String, dynamic> data = {'appversion': '1.5.10', 'gasType': 2};
  data = getParams(data, sessionid, false);
  var url = "https://api-accw.onethingpcs.com/wkb/draw";
  var header = {"Cookie": "sessionid=" + sessionid + "; userid=" + userid};
  var res = await post(url: url, header: header, data: data);
  if (res['iRet'] == 0) {
    return "1";
  } else {
    return res['sMsg'];
  }
}

Future<Map> getIncomeRecord({String sessionid, String userid, int year, int month}) async {
  var last_month;
  if (year == null && month == null) {
    last_month = "0";
  } else {
    if (year == null) year = new DateTime.now().year;
    if (month == null) month = new DateTime.now().month + 1;
    last_month = year.toString() + (month > 9 ? month.toString() : "0" + month.toString());
  }
  Map<String, dynamic> data = {'appversion': '1.5.10', 'last_month': last_month};
  data = getParams(data, sessionid, true);
  var url = "https://api-accw.onethingpcs.com/wkb/income-history";
  var header = {"Cookie": "sessionid=" + sessionid + "; userid=" + userid};
  var res = await get(url, data, header);
  if (res['iRet'] == 0) {
    return res['data'];
  } else {
    return null;
  }
}

Future<Map> getAccountInfo({String sessionid, String userid}) async {
  var url = "https://api-accw.onethingpcs.com/wkb/account-info";
  var header = {"Cookie": "sessionid=" + sessionid + "; userid=" + userid};
  var res = await post(url: url, header: header);
  if (res['iRet'] == 0) {
    return res['data'];
  } else {
    return null;
  }
}

Future<Map> getUsbInfo(String sessionid, String userid, String device_id) async {
  Map<String, dynamic> data = {'appversion': '1.5.10', 'ct': 1, 'deviceid': device_id, 'v': 1};
  data = getParams(data, sessionid, true);
  var url = "https://control.onethingpcs.com/getUSBInfo";
  var header = {"Cookie": "sessionid=" + sessionid + "; userid=" + userid};
  var res = await get(url, data, header);
  if (res['rtn'] != 0) {
    return null;
  } else {
    List disks = res['result'][1]['partitions'];
    int count = disks.length;
    double capacity = 0.0;
    double used = 0.0;
    disks.forEach((disk) {
      capacity += double.parse(disk['capacity']);
      used += double.parse(disk['used']);
    });
    Map usbInfo = {"count": count, "capacity": capacity.toString(), "used": used.toString()};
    return usbInfo;
  }
}
